//////////////////////////////////////////////////////////////////////////////////
//                                                                              //
//  This file is part of the buola project (https://code.google.com/p/buola/).  //
//                                                                              //
//  Copyright(c) 2007-2012 Xavi Gratal                                          //
//  gratal AT gmail DOT com                                                     //
//                                                                              //
//  Buola is free software: you can redistribute it and/or modify               //
//  it under the terms of the GNU General Public License as published by        //
//  the Free Software Foundation, either version 3 of the License, or           //
//  (at your option) any later version.                                         //
//                                                                              //
//  Buola is distributed in the hope that it will be useful,                    //
//  but WITHOUT ANY WARRANTY; without even the implied warranty of              //
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               //
//  GNU General Public License for more details.                                //
//                                                                              //
//  You should have received a copy of the GNU General Public License           //
//  along with buola.  If not, see <http://www.gnu.org/licenses/>.              //
//                                                                              //
//////////////////////////////////////////////////////////////////////////////////

#include <buola/utility/cdesktopfile.h>

#include <buola/io/cfile.h>
#include <buola/algorithm/split.h>
#include <buola/algorithm/trim.h>
#include <buola/algorithm/container.h>
#include <buola/io.h>

namespace buola {

CDesktopFile::CDesktopFile()
{
}

CDesktopFile::CDesktopFile(const io::CURI &pURI)
{
    Load(pURI);
}

CDesktopFile::~CDesktopFile()
{
    for(auto i=mGroups.begin();i!=mGroups.end();++i)
        delete i->second;
}

void CDesktopFile::Load(const io::CURI &pURI)
{
    io::PBufferStream lStream=io::CFile(pURI).GetBufferStream(io::EMode::READ);

    std::string lBuffer;

    TGroup *lGroup=nullptr;

    while(get_line(lStream,lBuffer))
    {
        trim_left(lBuffer);

        if(lBuffer[0]=='#') //comment
        {
            continue;
        }
        else if(lBuffer[0]=='[')
        {
            int lRight=lBuffer.find(']');
            if(lRight<0) throw XData(I18N("Badly-formed desktop entry"));

            lGroup=new TGroup;
            mGroups[lBuffer.substr(1,lRight-1)]=lGroup;
        }
        else if(std::isalnum(lBuffer[0]))
        {
            if(!lGroup) throw XData(I18N("Badly-formed desktop entry: no group"));
            
            int lEqual=lBuffer.find('=');

            std::string lName(lBuffer,0,lEqual);
            std::string lValue(lBuffer,lEqual+1);

            trim_right(lName);            //Remove space before =
            trim(lValue);
            (*lGroup)[lName]=lValue;
        }
    }
}

std::string *CDesktopFile::GetBest(const std::string &pGroup,const std::string &pKey)
{
    TGroup *lGroup=mGroups[pGroup];

    if(!lGroup)
    {
        msg_warn() << "group " << pGroup << " not found in ini file\n";
        return nullptr;
    }

    auto i=lGroup->find(pKey);
    if(i==lGroup->end())
        return nullptr;
    return &i->second;
}

bool CDesktopFile::Get(const std::string &pGroup,const std::string &pKey,
                                std::wstring &pValue,const std::wstring &pDefault)
{
    std::string *lFind=GetBest(pGroup,pKey);

    if(!lFind)
    {
        pValue=pDefault;
        return false;
    }
    pValue=utf32(*lFind);
    return true;
}

bool CDesktopFile::Get(const std::string &pGroup,const std::string &pKey,
                                std::string &pValue,const std::string &pDefault)
{
    std::string *lFind=GetBest(pGroup,pKey);

    if(!lFind)
    {
        pValue=pDefault;
        return false;
    }
    pValue=*lFind;
    return true;
}

bool CDesktopFile::Get(const std::string &pGroup,const std::string &pKey,
                                std::vector<std::string> &pValue)
{
    std::string *lFind=GetBest(pGroup,pKey);

    if(!lFind)
    {
        pValue.clear();
        return false;
    }
    split(*lFind,pValue,fn::equal_to(';'),nDeleteEmpty);
    return true;
}

const CDesktopFile::TGroup &CDesktopFile::GetGroup(const std::string &pName)
{
    TGroup *lGroup=mGroups[pName];

    if(!lGroup)
        throw XNotFound("group not found in desktop file");
    
    return *lGroup;
}

/*namespace buola*/ }
